package e.odbo.data.generator;

import java.util.List;
import java.util.Vector;
import java.util.regex.Pattern;

public class CardNumberGenerator extends Generator<String>{
    protected   String[] prefixList;
    protected   int length;

    public CardNumberGenerator(String[] prefix, int length) {
        this.prefixList = prefix;
        this.length = length;
    }

    public CardNumberGenerator(String prefix, int length) {
        this.prefixList = new String[]{prefix};
        this.length = length;
    }

    @Override
    public String generator() {
        int randomArrayIndex=0;
        if(prefixList.length>1)
            randomArrayIndex = (int) Math.floor(Math.random()* prefixList.length);
        String ccnumber = prefixList[randomArrayIndex];
        return ccnumber+completed_number(null, length -prefixList.length);
    }

    @Override
    public String getName() {
        return "CardNumber";
    }

    static String strrev(String str) {
        if (str == null)
            return "";
        String revstr = "";
        for (int i = str.length() - 1; i >= 0; i--) {
            revstr += str.charAt(i);
        }
        return revstr;
    }

    /*
     * 'prefix' is the start of the CC number as a string, any number of digits.
     * 'length' is the length of the CC number to generate. Typically 13 or 16
     */
   protected static String completed_number(String prefix, int length) {
        String ccnumber = prefix==null?"":prefix;
        // generate digits
        while (ccnumber.length() < (length - 1)) {
            ccnumber += new Double(Math.floor(Math.random() * 10)).intValue();
        }
        // reverse number and convert to int
        String reversedCCnumberString = strrev(ccnumber);
        List<Integer> reversedCCnumberList = new Vector<Integer>();
        for (int i = 0; i < reversedCCnumberString.length(); i++) {
            reversedCCnumberList.add(new Integer(String.valueOf(reversedCCnumberString.charAt(i))));
        }
        // calculate sum
        int sum = 0;
        int pos = 0;
        Integer[] reversedCCnumber = reversedCCnumberList
                .toArray(new Integer[reversedCCnumberList.size()]);
        while (pos < length - 1) {
            int odd = reversedCCnumber[pos] * 2;
            if (odd > 9) {
                odd -= 9;
            }
            sum += odd;
            if (pos != (length - 2)) {
                sum += reversedCCnumber[pos + 1];
            }
            pos += 2;
        }
        // calculate check digit
        int checkdigit = new Double(
                ((Math.floor(sum / 10) + 1) * 10 - sum) % 10).intValue();
        ccnumber += checkdigit;
        return ccnumber;
    }

    public boolean isCardNumber(String creditCardNumber) {
        boolean isValid = false;
        if(prefixList.length==1)
            creditCardNumber=creditCardNumber.substring(prefixList[0].length());
        else{
            Pattern pattern=null;
            for(String prefix:prefixList){
                pattern=Pattern.compile("^"+prefix+"\\d+$");
                if(pattern.matcher(creditCardNumber).matches()) {
                    creditCardNumber=creditCardNumber.substring(prefix.length());
                }
            }
        }
        return isValidCreditCardNumber(creditCardNumber);
    }

    public  static boolean isValidCreditCardNumber(String creditCardNumber) {
        boolean isValid = false;

        try {
            String reversedNumber = new StringBuffer(creditCardNumber)
                    .reverse().toString();
            int mod10Count = 0;
            for (int i = 0; i < reversedNumber.length(); i++) {
                int augend = Integer.parseInt(String.valueOf(reversedNumber
                        .charAt(i)));
                if (((i + 1) % 2) == 0) {
                    String productString = String.valueOf(augend * 2);
                    augend = 0;
                    for (int j = 0; j < productString.length(); j++) {
                        augend += Integer.parseInt(String.valueOf(productString
                                .charAt(j)));
                    }
                }

                mod10Count += augend;
            }

            if ((mod10Count % 10) == 0) {
                isValid = true;
            }
        } catch (NumberFormatException e) {
        }

        return isValid;
    }
}
